﻿using System;
using System.Windows.Forms;
using accesoDatos;
using System.Data;

namespace clasesBase
{
    /* Formulario base que reúne funcionalidad común a todos los formularios de búsqueda, generalizando el comportamiento
     * de los mismos. Presenta una grilla que contendrá los datos, botones de ABM (donde sólo la baja se realiza en este punto
     y los demás se realizan en formularios aparte), botón para imprimir, filtrar y salir. */
    public partial class FrmBusquedas : Form
    {
        // Controla si el usuario puede realizar la acción de exportar la información contenida en la grilla
        // Por defecto, se le permite siempre
        private bool permitirExportar = true;
        public bool PermitirExportar
        {
            set { this.permitirExportar = value; }
        }

        public FrmBusquedas()
        {
            InitializeComponent();
        }

        #region Parámetros del formulario
        // Variables utilizadas para el filtrado de datos
        protected string[] columnasFiltro = new string[] { }, valoresFiltro = new string[] { };
        protected char[] tiposDeDatos = new char[] { };
        private int ultimoIndiceColumnaOrdenGrilla = -1;
        private string ultimoTipoOrden = "ASC";

        // Variable utilizada para conocer la fila actualmente seleccionada en la grilla
        protected DataGridViewRow filaSeleccionada = null;
        public DataGridViewRow FilaSeleccionada
        {
            get { return filaSeleccionada; }
        }

        // Datos necesarios para la consulta de los datos y la obtención del id de la misma
        protected string tablaBD = "", nombreColumnaID = "id";
        protected bool obtenerDatosGenerico = true;
        #endregion

        #region Mensaje de espera
        protected void mostrarMsjEspera()
        {
            Cursor = Cursors.WaitCursor;
            mensajeEspera.Visible = true;
            this.Refresh();
        }

        protected void limpiarMsjEspera()
        {
            Cursor = Cursors.Default;
            mensajeEspera.Visible = false;
        }
        #endregion

        #region Filtrado de datos
        protected void btnTodos_Click(object sender, EventArgs e)
        {
            FiltroBindingSource.mostrarTodo(datos);

            limpiarFiltros();

            mostrarCantidadDatos();
        }

        private void limpiarFiltros()
        {
            foreach (Control controlHijo in this.grupoFiltros.Controls)
            {
                if ((controlHijo is TextBox) || (controlHijo is MaskedTextBox))
                    controlHijo.Text = "";

                if (controlHijo is CheckBox)
                {
                    CheckBox check = (CheckBox)controlHijo;
                    check.Checked = false;
                }
            }

        }

        protected void btnFiltros_Click(object sender, EventArgs e)
        {
            string error = FiltroBindingSource.aplicarFiltrosVarios(datos, this.columnasFiltro, this.valoresFiltro, this.tiposDeDatos);
            if (error.Trim() != "") Notificador.errorAlFiltrar(error);

            mostrarCantidadDatos();
        }

        private void mostrarCantidadDatos()
        {
            txtCantidadElementos.Text = datos.Count.ToString();
        }
        #endregion

        /* IMPORTANTE: los hijos deben establecer estos valores para el correcto funcionamiento del formulario */
        protected void establecerValoresFormulario(string tablaDatosConsultada, string nombreColumnaId, string[] columnasMostrarGrilla)
        {
            this.tablaBD = tablaDatosConsultada;
            this.nombreColumnaID = nombreColumnaId;
            this.definirColumnasGrilla(columnasMostrarGrilla);
            this.btnExportarXLS.Visible = this.permitirExportar;
        }

        /* Método que recibe un arreglo con las cadenas que representan los nombres de las columnas que se desean 
         * mostrar en la grilla.
         * Cada cadena debe ser igual al nombre de la columna de la tabla de la BD que se está consultando, aunque
         * se permiten espacios para separar palabras y acentos. */
        private void definirColumnasGrilla(string[] columnasMostrarGrilla)
        {
            DataGridViewCell celda = new DataGridViewTextBoxCell();
            grilla.Columns.Clear();
            int cantColumnas = columnasMostrarGrilla.Length;
            for (int indiceCol = 0; indiceCol < cantColumnas; indiceCol++)
            {
                DataGridViewColumn columna = new DataGridViewColumn(celda);
                columna.HeaderText = columnasMostrarGrilla[indiceCol];
                columna.Name = Validador.quitarCaracteresEspeciales(columnasMostrarGrilla[indiceCol]);
                columna.DataPropertyName = Validador.quitarCaracteresEspeciales(columnasMostrarGrilla[indiceCol]);

                grilla.Columns.Add(columna);
            }

            grilla.AutoGenerateColumns = false;
        }

        protected DataGridViewRow getFilaSeleccionada()
        {
            this.filaSeleccionada = null; // Se define un valor por defecto

            if (grilla.Rows.Count > 0) this.filaSeleccionada = grilla.CurrentRow;
            else Notificador.elementoNoSeleccionado();

            return this.filaSeleccionada;
        }

        public int obtenerIdSeleccionado()
        {
            int idElemento = 0;
            DataGridViewRow filaSeleccionada = getFilaSeleccionada();
            if (filaSeleccionada != null) idElemento = int.Parse(filaSeleccionada.Cells[this.nombreColumnaID].Value.ToString());
            return idElemento;
        }

        private void btnSalir_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        protected bool existenDatos()
        {
            return (datos.Count > 0);
        }

        protected void obtenerDatos()
        {
            datos.DataSource = EntidadAlmacenable.listarElementos(this.tablaBD, this.columnasFiltro, this.valoresFiltro);
            ajustarTamanioGrilla();
            mostrarCantidadDatos();
        }

        protected void abrirFormDetalle<T>(object sender, bool soloVisualizar) where T : FrmABM
        {
            bool permitirEdicion = true;
            abrirFormDetalle<T>(sender, soloVisualizar, permitirEdicion);
        }

        protected void abrirFormDetalle<T>(object sender, bool soloVisualizar, bool permitirEdicion) where T : FrmABM
        {
            int idElemento = 0;
            bool abrirFormulario = true;

            if (sender != null) // Si es null, se lo llama desde otro evento no desencadenado de un botón ABM (ejemplo: doble click grilla)
            {
                // Según la acción que se desea realizar (nuevo o modificar) se establece el valor del idElemento
                Button boton = (Button)sender;
                switch (boton.Name)
                {
                    case "btnNuevo":
                        idElemento = 0;
                        break;
                    case "btnEditar":
                        idElemento = obtenerIdSeleccionado();
                        if (idElemento == 0) abrirFormulario = false;
                        break;
                    default:
                        abrirFormulario = true;
                        break;
                }
            }
            else idElemento = obtenerIdSeleccionado();

            if (abrirFormulario)
            {
                mostrarFormulario<T>(idElemento, soloVisualizar, permitirEdicion);
                if (obtenerDatosGenerico) obtenerDatos();
            }
        }

        private void mostrarFormulario<T>(int idElem, bool soloVisualizar, bool permitirEdicion) where T : FrmABM
        {
            T formDetalle = FormsUnicos.ObtenerInstancia<T>(this);
            formDetalle.IdElemento = idElem;
            formDetalle.SoloVisualizacion = soloVisualizar;
            formDetalle.PermitirEdicion = permitirEdicion;
            formDetalle.ShowDialog();
        }

        protected void ajustarTamanioGrilla()
        {
            grilla.Width = grupoResultados.Width;
        }

        protected virtual void grilla_DoubleClick(object sender, EventArgs e)
        {
            /* Sólo existe este método para que las clases hijas puedan heredarlo y sobreescribirlo,
             * asegurando de esta manera poder utilizar este evento. De otra manera, no se permitía
             * personalizar el comportamiento de la grilla al recibir un doble clic.
             */
        }

        private void FrmBusquedas_Load(object sender, EventArgs e)
        {
            grilla.Enabled = true;
        }

        private void grilla_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
        {
            int indiceColumnaAOrdenar = e.ColumnIndex;

            if (indiceColumnaAOrdenar == ultimoIndiceColumnaOrdenGrilla)
            {
                if (ultimoTipoOrden.Equals("ASC")) ultimoTipoOrden = "DESC";
                else ultimoTipoOrden = "ASC";
            }
            else ultimoIndiceColumnaOrdenGrilla = indiceColumnaAOrdenar;

            datos.Sort = string.Format("{0} {1}", grilla.Columns[indiceColumnaAOrdenar].Name, ultimoTipoOrden);
        }

        private void btnExportar_Click(object sender, EventArgs e)
        {
            if (grilla.Rows.Count > 0)
            {
                string titulo_archivo = this.Text.Replace("Búsqueda de", "");
                string path_archivo = ManejadorPath.obtenerRutaGuardarArchivo(titulo_archivo, "Excel");
                if (path_archivo != "")
                {
                    ExportaExcel excel = new ExportaExcel(grilla, path_archivo, titulo_archivo);
                }
            }
            else Notificador.grillaVacia();
        }
    }
}